package com.wider.services.impl;

import com.wider.pojo.BaseData;
import com.wider.pojo.MinAndMax;
import com.wider.pojo.WideData;
import com.wider.services.BaseDataService;
import com.wider.services.DataService;
import com.wider.services.FlowServices;
import com.wider.services.WideDataService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.sql.DataSource;
import java.math.BigDecimal;
import java.sql.Connection;
import java.sql.SQLException;
import java.sql.Statement;
import java.time.Duration;
import java.time.LocalDateTime;
import java.time.temporal.ChronoUnit;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author Maple
 */
//@Service
public class FlowServicesImpl {

    List<Integer> jis = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 15, 20, 30, 60, 120, 240);

//    @Autowired
    DataService dataService;

//    @Autowired
    BaseDataService baseDataService;

//    @Autowired
    WideDataService wideService;

//    @Autowired
    DataSource dataSource;

    public static List<String> processingCaseNameList = new ArrayList<>();

    public boolean processingData(LocalDateTime processtime, String caseName) {
        /**
         * 关于后续优化方案
         * 1. 请使用多线程执行，可以尝试分割任务，获取到第一个小时信息，反正都是读取，不存在脏的问题
         * 2.减少ORM操作，但是对于这个的话，需要思考程序的数据从哪里获取，或者一次性将当前一小时的前4小时后四小时数据全部走内存
         *              也可以将关于写入的ORM进行批量操作，当每个小时的数据都独立运行的话，就是查询的时候，需要排序
         * 3.优化代码速度，这个要对代码研究时间更长，更快更简洁进行操作，单个时间下来了，批处理的时间下来得更快
         * 4.干脆去掉MySQL,每个数据都走文件，如果发现跨文件，则触发读取。很难说，但是应该能解决ORM时间问题
         */
        WideData wideData = new WideData();
        List<BaseData> nowResult = baseDataService.getBaseData(processtime, processtime.plusSeconds(59), caseName);
        if (null == nowResult || nowResult.isEmpty()) {
            return true;
        }
        wideData.setDateTime(processtime);
        List<BigDecimal> collect = nowResult.stream().map(BaseData::getData).collect(Collectors.toList());
        BigDecimal median = dataService.findMedian(collect);
        MinAndMax minAndMax1 = dataService.getMinAndMax(collect);
        wideData.setMinData(minAndMax1.getMinValue());
        wideData.setMaxData(minAndMax1.getMaxValue());
        wideData.setNowData(median);
        for (Integer i : jis) {
            LocalDateTime startTime = processtime.plusMinutes(i);
            List<BaseData> data = baseDataService.getBaseData(startTime, startTime.plusSeconds(59), caseName);
            if (data.isEmpty()) {
                continue;
            }
            List<BigDecimal> bigDecimalList = data.stream().map(BaseData::getData).collect(Collectors.toList());
            MinAndMax minAndMax = dataService.getMinAndMax(bigDecimalList);
            BigDecimal meaningfulValues = dataService.getMeaningfulValues(minAndMax, median);
            meaningfulValues = dataService.formulaCalculation(meaningfulValues, median);
            switch (i) {
                case 1:
                    wideData.setFuture01min(meaningfulValues);
                    break;
                case 2:
                    wideData.setFuture02min(meaningfulValues);
                    break;
                case 3:
                    wideData.setFuture03min(meaningfulValues);
                    break;
                case 4:
                    wideData.setFuture04min(meaningfulValues);
                    break;
                case 5:
                    wideData.setFuture05min(meaningfulValues);
                    break;
                case 6:
                    wideData.setFuture06min(meaningfulValues);
                    break;
                case 7:
                    wideData.setFuture07min(meaningfulValues);
                    break;
                case 8:
                    wideData.setFuture08min(meaningfulValues);
                    break;
                case 9:
                    wideData.setFuture09min(meaningfulValues);
                    break;
                case 10:
                    wideData.setFuture10min(meaningfulValues);
                    break;
                case 15:
                    wideData.setFuture15min(meaningfulValues);
                    break;
                case 20:
                    wideData.setFuture20min(meaningfulValues);
                    break;
                case 30:
                    wideData.setFuture30min(meaningfulValues);
                    break;
                case 60:
                    wideData.setFuture60min(meaningfulValues);
                    break;
                case 120:
                    wideData.setFuture120min(meaningfulValues);
                    break;
                case 240:
                    wideData.setFuture240min(meaningfulValues);
                    break;
            }
        }
        for (Integer i : jis) {
            LocalDateTime startTime = processtime.minusMinutes(i);
            List<BaseData> data = baseDataService.getBaseData(startTime, startTime.plusSeconds(59), caseName);
            if (data.isEmpty()) {
                continue;
            }
            List<BigDecimal> bigDecimalList = data.stream().map(BaseData::getData).collect(Collectors.toList());
            MinAndMax minAndMax = dataService.getMinAndMax(bigDecimalList);
            BigDecimal meaningfulValues = dataService.getMeaningfulValues(minAndMax, median);
            meaningfulValues = dataService.formulaCalculation(meaningfulValues, median);
            switch (i) {
                case 1:
                    wideData.setPast01min(meaningfulValues);
                    break;
                case 2:
                    wideData.setPast02min(meaningfulValues);
                    break;
                case 3:
                    wideData.setPast03min(meaningfulValues);
                    break;
                case 4:
                    wideData.setPast04min(meaningfulValues);
                    break;
                case 5:
                    wideData.setPast05min(meaningfulValues);
                    break;
                case 6:
                    wideData.setPast06min(meaningfulValues);
                    break;
                case 7:
                    wideData.setPast07min(meaningfulValues);
                    break;
                case 8:
                    wideData.setPast08min(meaningfulValues);
                    break;
                case 9:
                    wideData.setPast09min(meaningfulValues);
                    break;
                case 10:
                    wideData.setPast10min(meaningfulValues);
                    break;
                case 15:
                    wideData.setPast15min(meaningfulValues);
                    break;
                case 20:
                    wideData.setPast20min(meaningfulValues);
                    break;
                case 30:
                    wideData.setPast30min(meaningfulValues);
                    break;
                case 60:
                    wideData.setPast60min(meaningfulValues);
                    break;
                case 120:
                    wideData.setPast120min(meaningfulValues);
                    break;
                case 240:
                    wideData.setPast240min(meaningfulValues);
                    break;
            }
        }
        Boolean b = wideService.saveOne(wideData, caseName);
        System.err.println("wideTable insert caseName" + caseName + " result = " + b);
        return false;
    }

    public void processingData(List<BaseData> baseDataList, LocalDateTime processTime, String caseName) {
        throw new RuntimeException();
    }

    public void ddlRunner(String caseName) {

        Connection conn = null;
        try {
            conn = dataSource.getConnection();
            Statement statement = conn.createStatement();
            statement.execute("drop table if exists " + caseName + "_baseData;\n");
            statement.execute("drop table if exists " + caseName + "_wideData;\n");
            String caseSql = "create table if not exists startSQL." + caseName + "_baseData\n" +
                    "(\n" +
                    "    date datetime       not null comment 'BaseDataDate',\n" +
                    "    data decimal(30, 10) not null comment 'BaseData'\n" +
                    ")  ENGINE = MEMORY;";
            statement.execute(caseSql);
            String caseSql2 = "create table if not exists startSQL." + caseName + "_wideData\n" +
                    "(\n" +
                    "    past240min   decimal(30, 10) null,\n" +
                    "    past120min   decimal(30, 10) null,\n" +
                    "    past60min    decimal(30, 10) null,\n" +
                    "    past30min    decimal(30, 10) null,\n" +
                    "    past20min    decimal(30, 10) null,\n" +
                    "    past15min    decimal(30, 10) null,\n" +
                    "    past10min    decimal(30, 10) null,\n" +
                    "    past09min    decimal(30, 10) null,\n" +
                    "    past08min    decimal(30, 10) null,\n" +
                    "    past07min    decimal(30, 10) null,\n" +
                    "    past06min    decimal(30, 10) null,\n" +
                    "    past05min    decimal(30, 10) null,\n" +
                    "    past04min    decimal(30, 10) null,\n" +
                    "    past03min    decimal(30, 10) null,\n" +
                    "    past02min    decimal(30, 10) null,\n" +
                    "    past01min    decimal(30, 10) null,\n" +
                    "    date_time    datetime       not null,\n" +
                    "    now_data     decimal(30, 10) not null,\n" +
                    "    min_data     decimal(30, 10) not null,\n" +
                    "    max_data     decimal(30, 10) not null,\n" +
                    "    future01min  decimal(30, 10) null,\n" +
                    "    future02min  decimal(30, 10) null,\n" +
                    "    future03min  decimal(30, 10) null,\n" +
                    "    future04min  decimal(30, 10) null,\n" +
                    "    future05min  decimal(30, 10) null,\n" +
                    "    future06min  decimal(30, 10) null,\n" +
                    "    future07min  decimal(30, 10) null,\n" +
                    "    future08min  decimal(30, 10) null,\n" +
                    "    future09min  decimal(30, 10) null,\n" +
                    "    future10min  decimal(30, 10) null,\n" +
                    "    future15min  decimal(30, 10) null,\n" +
                    "    future20min  decimal(30, 10) null,\n" +
                    "    future30min  decimal(30, 10) null,\n" +
                    "    future60min  decimal(30, 10) null,\n" +
                    "    future120min decimal(30, 10) null,\n" +
                    "    future240min decimal(30, 10) null\n" +
                    ") ENGINE = MEMORY;";
            statement.execute(caseSql2);
        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }

    public void processingData(String caseName) {
        System.err.println("caseName" + caseName + "数据插入完成，进入数据处理阶段");
        processingCaseNameList.add(caseName);
        LocalDateTime startTime = LocalDateTime.now();
        LocalDateTime updateTime;
        BaseData firstBaseData = baseDataService.getFirstBaseData(caseName);
        LocalDateTime date = firstBaseData.getDate();
        date = date.truncatedTo(ChronoUnit.MINUTES);
        BaseData finallyData = baseDataService.getFinallyBaseData(caseName);
        boolean end = false;
        while (date.isBefore(finallyData.getDate())) {
            while (!end) {
                updateTime = LocalDateTime.now();
                end = processingData(date,caseName);
                date = date.plusMinutes(1);
                Duration duration = Duration.between(updateTime, LocalDateTime.now());
                System.err.println("处理一轮时间为" + duration.toMillis() + "毫秒钟！");
            }
            end = false;
            BaseData nextBaseData = baseDataService.getNextBaseData(date, caseName);
            if (null != nextBaseData) {
                date = nextBaseData.getDate();
                while (!end) {
                    updateTime = LocalDateTime.now();
                    end = processingData(date,caseName);
                    date = date.plusMinutes(1);
                    Duration duration = Duration.between(updateTime, LocalDateTime.now());
                    System.err.println("处理一轮时间为" + duration.toMillis() + "毫秒钟！");
                }
            }
        }
        processingCaseNameList.remove(caseName);
        Duration duration = Duration.between(startTime, LocalDateTime.now());
        System.err.println("当前caseName:" + caseName + "处理全部时间为" + duration.getSeconds() + "秒！");
    }
}

